package com.zjuee.core.utils;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import com.zjuee.base.bean.response.CommonResultCode;
import com.zjuee.base.exception.BaseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.namespace.QName;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author wuliang
 * @date 2020/03/19
 */
public class RetryingUtil implements Runnable{

    private static final Logger log = LoggerFactory.getLogger(RetryingUtil.class);

    private String jsonData;

    private String arg1;

    private String wsdlUrl;

    private String methonName;

    private Map<String,Object> retryMap;

    //返回结果
    private String result;

    /**
     * 动态调用方式-重发
     * @param jsonData 传输数据
     * @param wsdlUrl wsdl地址
     * @param methonName 方法名
     * @param retryMap 重发参数 - 重发次数：retryNum, 重发间隔时间(秒)： retryIntervalTime
     */
    public String retryMessage(String jsonData, String wsdlUrl, String methonName, Map<String,Object> retryMap)  {
        retryMessage(jsonData, "", wsdlUrl, methonName, retryMap);
        return result;
    }

    /**
     * 动态调用方式-重发
     * @param jsonData 第一个参数 - 传输数据
     * @param arg1 第二个参数
     * @param wsdlUrl wsdl地址
     * @param methonName 方法名
     * @param retryMap 重发参数 - 重发次数：retryNum, 重发间隔时间(秒)： retryIntervalTime
     * @return
     */
    public String retryMessage(String jsonData,String arg1, String wsdlUrl, String methonName, Map<String,Object> retryMap)  {
        this.jsonData = jsonData;
        this.arg1 = arg1;
        this.wsdlUrl = wsdlUrl;
        this.methonName = methonName;
        this.retryMap = retryMap;
        //发送数据
        sendMessage();
        return result;
    }

    /**
     * 动态调用方式-不重发
     * @param jsonData 传输数据
     * @param wsdlUrl wsdl地址
     * @param methonName 方法名
     */
    public String send(String jsonData, String wsdlUrl, String methonName)  {
        sendMessage(jsonData, "", wsdlUrl, methonName);
        return result;
    }

    /**
     * 动态调用方式-不重发
     * @param jsonData 第一个参数 - 传输数据
     * @param arg1 第二个参数
     * @param wsdlUrl wsdl地址
     * @param methonName 方法名
     */
    public String send(String jsonData, String arg1, String wsdlUrl, String methonName)  {
        sendMessage(jsonData, arg1, wsdlUrl, methonName);
        return result;
    }

    /**
     * 发送信息 - 重发
     * @return
     */
    private void sendMessage(){

//        Client client = null;
        try {
            // 创建动态客户端
//            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
//            client = dcf
//                .createClient(wsdlUrl);

            Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                //抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
                .retryIfException()
                //返回false也需要重试
                .retryIfResult(Predicates.equalTo(false))
                //重调策略
                .withWaitStrategy(WaitStrategies.fixedWait(Long.valueOf(String.valueOf(retryMap.get("retryIntervalTime"))), TimeUnit.SECONDS))
                //尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(Integer.valueOf(String.valueOf(retryMap.get("retryNum")))))
                .build();
            retryer.call(() -> {
                JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
                Client client = dcf.createClient(wsdlUrl);
                HTTPConduit http = (HTTPConduit) client.getConduit();
                HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
                httpClientPolicy.setConnectionTimeout(20000);  //连接超时
                httpClientPolicy.setAllowChunking(false);    //取消块编码
                httpClientPolicy.setReceiveTimeout(20000);     //响应超时
                http.setClient(httpClientPolicy);
                QName qName = new QName("http://service.transfer.dataInsert.webService.core.g20.streetlight.org");
                result = parse(client.invoke(qName,methonName, jsonData, arg1)
                );
                client.close();
                return true;
            });

        } catch (Exception e) {
            e.printStackTrace();
            log.error("Error Retring Found" + e.getMessage());
            log.error("Error Retring Found" , e);
            Throwable cause = e.getCause();
            if(cause !=null  && StringUtils.isNotBlank(cause.getMessage())) {
                if (cause.getMessage().indexOf("Connection refused: connect") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "连接省平台异常，请联系管理员");
                } else if (cause.getMessage().indexOf("Read timed out") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-响应超时，请联系管理员");
                } else if (cause.getMessage().indexOf("connect timed out") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-连接超时，请联系管理员");
                } else if (cause.getMessage().indexOf("Could not receive Message") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-响应超时，请联系管理员");
                }
            }
            throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台错误，请联系管理员");
        }
//        finally {
//            if(client != null){
//                try {
//                    client.close();
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//        }
    }

    private void sendMessage(String jsonData, String arg1, String wsdlUrl, String methonName){
        Object[] objects = null;
        Client client = null;
        try {
            // 创建动态客户端
            JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
            QName qName = new QName("http://service.transfer.dataInsert.webService.core.g20.streetlight.org","");
            client = dcf
                    .createClient(wsdlUrl);
            Endpoint endpoint = client.getEndpoint();

            //设置超时单位为毫秒
            HTTPConduit http = (HTTPConduit) client.getConduit();
            HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
            httpClientPolicy.setConnectionTimeout(20000);  //连接超时
            httpClientPolicy.setAllowChunking(false);    //取消块编码
            httpClientPolicy.setReceiveTimeout(20000);     //响应超时
            http.setClient(httpClientPolicy);
//            QName qName = new QName(endpoint.getService().getName().getNamespaceURI(),"");
//            BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();
//            if(bindingInfo.getOperation(qName) == null){
//            }
            objects = client.invoke(methonName, jsonData, arg1);
            result =  (String) objects[0];
        }catch (Exception e) {
            e.printStackTrace();
            log.error("Error Retring Found" + e.getMessage());
            log.error("Error Retring Found" , e);
            Throwable cause = e.getCause();
            if(cause !=null  && StringUtils.isNotBlank(cause.getMessage())) {
                if (cause.getMessage().indexOf("Connection refused: connect") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "连接省平台异常，请联系管理员");
                } else if (cause.getMessage().indexOf("Read timed out") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-响应超时，请联系管理员");
                } else if (cause.getMessage().indexOf("connect timed out") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-连接超时，请联系管理员");
                } else if (cause.getMessage().indexOf("Could not receive Message") > 0) {
                    throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台-响应超时，请联系管理员");
                }
            }
            throw new BaseException(CommonResultCode.CONSUMER_ERR, "发送省平台错误，请联系管理员");
        }finally {
            if(client != null){
                try {
                    client.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //解析返回数据
    private String  parse(Object[] obj){
        System.out.println(obj);
        for (Object o : obj){
            System.out.println(obj.toString());
        }
        return (String) obj[0];
    }

    private String  packData(String methonName, String jsonData){
        //拼接数据
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("<?xml version=\"1.0\" ?>");
        stringBuffer.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
        stringBuffer.append("<soapenv:Header>");
        stringBuffer.append("<arg0 xsi:type=\"xsd:string\">1</arg0>");
        stringBuffer.append("</soapenv:Header>");
        stringBuffer.append("<soapenv:Body>");
        stringBuffer.append("<ns1:");
        stringBuffer.append(methonName);
        stringBuffer.append(" xmlns:ns1=\"http://service.inter.maviki.tempetek.com/\" soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">");
        stringBuffer.append("<arg0 xsi:type=\"xsd:string\">");
        stringBuffer.append(jsonData);
        stringBuffer.append("</arg0>");
        stringBuffer.append("</ns1:");
        stringBuffer.append(methonName);
        stringBuffer.append("></soapenv:Body>");
        stringBuffer.append("</soapenv:Envelope>");
        return stringBuffer.toString();
    }

    @Override
    public void run() {
        retryMessage(jsonData, wsdlUrl, methonName, retryMap);
    }
}